package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.openea.perpartner.common.core.exception.ServiceException;
import cn.openea.perpartner.common.core.utils.StringUtils;
import cn.openea.perpartner.common.redis.service.RedisCache;
import cn.openea.perpartner.meily.web.entity.Role;
import cn.openea.perpartner.meily.web.entity.RoleMenu;
import cn.openea.perpartner.meily.web.entity.User;
import cn.openea.perpartner.meily.web.entity.UserRole;
import cn.openea.perpartner.meily.web.entity.dto.UserRoleDto;
import cn.openea.perpartner.meily.web.entity.vo.UserVo;
import cn.openea.perpartner.meily.web.mapper.UserMapper;
import cn.openea.perpartner.meily.web.service.IUserRoleService;
import cn.openea.perpartner.meily.web.service.IUserService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;

/**
 * (User)表服务实现类
 *
 * @author Weird077
 * @since 2023-03-15 16:17:55
 */
@Slf4j
@Service("userService")
public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implements IUserService {

    @Value("${payment.order.authSalt}")
    private String authSalt;
    @Value("${payment.order.getTokenUrl}")
    private String getOrderSysTokenUrl;
    @Value("${payment.order.emptyWalletUrl}")
    private String emptyWalletUrl;
    @Value("${payment.order.getCoinsUrl}")
    private String getCoinsUrl;
    @Value("${sysuser.reset_pwd_url}")
    private String resetPwdUrl;
    @Value("${sso.url}")
    private String ssoUrl;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IUserRoleService userRoleService;

    @Override
    public boolean insertUser(User user) {

        return saveOrUpdate(user);
    }

    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    @Override
    public boolean updateUser(User user) {
        String userId = user.getUserId();
        // 删除用户与角色关联
        userRoleService.deleteUserRoleByUserId(userId);
        // 新增用户与角色关联
        insertUserRole(userId, user.getRoleIds());
        // 更新用户信息
        return saveOrUpdate(user);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public void insertUserAuth(String userId, Long[] roleIds) {
        // 删除用户与角色关联
        userRoleService.deleteUserRoleByUserId(userId);
        // 新增用户与角色管理
        insertUserRole(userId, roleIds);
    }

    @Override
    public List<User> selectAllocatedList(UserRoleDto dto) {
        MPJLambdaWrapper<User> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(User.class)
                .leftJoin(UserRole.class, UserRole::getUserId, User::getUserId)
                .leftJoin(Role.class, Role::getRoleId, UserRole::getRoleId)
                .eq(Role::getRoleId, dto.getRoleId());
        if (StrUtil.isNotBlank(dto.getUserId())) {
            wrapper.like(User::getUserId, dto.getUserId());
        }
        if (StrUtil.isNotBlank(dto.getUserName())) {
            wrapper.like(User::getUserName, dto.getUserName());
        }
        wrapper.orderByDesc(User::getCreateTime);
        return list(wrapper);
    }

    @Override
    public List<User> selectUnallocatedList(UserRoleDto dto) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        StringBuilder sb = new StringBuilder();
        sb.append(" (r.role_id != ").append(dto.getRoleId()).append(" or r.role_id IS NULL)");
        sb.append(" and u.user_id not in (select u.user_id from meily_user u inner join meily_user_role ur on u.user_id = ur.user_id and ur.role_id = ").append(dto.getRoleId()).append(")");
        if (StrUtil.isNotBlank(dto.getUserId())) {
            sb.append(" AND u.user_id like concat('%', '").append(dto.getUserId()).append("', '%')");
        }
        if (StrUtil.isNotBlank(dto.getUserName())) {
            sb.append(" AND u.user_name like concat('%', '").append(dto.getUserName()).append("', '%')");
        }
        sb.append(" order by u.create_time desc");
        wrapper.last(sb.toString());
        return baseMapper.selectUnallocatedList(wrapper);
    }

    @Override
    public List<User> selectUserlist(User user) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(user.getIdentity())) {
            wrapper.eq(User::getIdentity, user.getIdentity());
        }
        if (StrUtil.isNotBlank(user.getUserId())) {
            wrapper.like(User::getUserId, user.getUserId());
        }
        if (StrUtil.isNotBlank(user.getUserName())) {
            wrapper.like(User::getUserName, user.getUserName());
        }
        wrapper.orderByDesc(User::getCreateTime);
        return list(wrapper);
    }

    /**
     * 新增用户角色信息
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    public void insertUserRole(String userId, Long[] roleIds) {
        if (StringUtils.isNotNull(roleIds)) {
            // 新增用户与角色管理
            List<UserRole> list = new ArrayList<>();
            for (Long roleId : roleIds) {
                UserRole ur = new UserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            if (!list.isEmpty()) {
                userRoleService.saveBatch(list);
            }
        }
    }

    /**
     * 新增/修改员工详情
     *
     * @param userVo
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    @Override
    public boolean updateStaff(UserVo userVo) {

        User user = new User();
        BeanUtil.copyProperties(userVo, user);

        if (userVo == null || user == null) {
            return false;
        }

        // 重置密码
        if (StrUtil.isNotBlank(userVo.getNewPassword())) {
            JSONObject object = new JSONObject();
            object.put("userid", user.getUserId());// 用户id
            object.put("password", userVo.getNewPassword());// 新密码
            JSONObject resObj = resetPwd(object);
            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                throw new ServiceException("重置密码出错了！");
            }
        }

        // 清空钱包
        if (StrUtil.isNotBlank(userVo.getEmptyWallet()) && "1".equals(userVo.getEmptyWallet())) {
            JSONObject object = new JSONObject();
            object.put("userId", user.getUserId());// 用户id
            object = getToken(object);

            System.out.println("getToken后的参数为：" + object);

            JSONObject resObj = paymentAPI(object, emptyWalletUrl);

            System.out.println("resObj：" + resObj);

            if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                throw new ServiceException("清空钱包出错了！");
            }
        }

        // 更新用户信息
        return saveOrUpdate(user);
    }

    /**
     * 获取钱包余额
     *
     * @param userVo
     * @return
     */
    @Override
    public String getCoins(UserVo userVo) {
        JSONObject object = new JSONObject();
        object.put("userId", userVo.getUserId());// 用户id
        object = getToken(object);
        JSONObject resObj = paymentAPI(object, getCoinsUrl);
        if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
            throw new ServiceException("获取钱包余额出错了！");
        }

        String Coins = "";
        if (StrUtil.isNotBlank(resObj.getString("data"))) {
            Coins = resObj.getString("data");
        }
        return Coins;
    }

    /**
     * 获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public User getUserInfoById(String userId) {
        User user = new User();
        // 从缓存获取
        String key = this.getCacheKey(userId);
        if (Boolean.TRUE.equals(redisCache.hasKey(key))) {
            log.info("从缓存获取用户信息（" + userId + "）===" + redisCache.getCacheObject(key));
            if (redisCache.getCacheObject(key) == null) {
                // 缓存中获取不到，再调接口获取
                JSONObject resObj = getUserCache(userId);
                if (resObj.isEmpty() || !"200".equals(resObj.getString("code"))) {
                    throw new ServiceException("获取用户信息出错了！");
                }
                JSONObject obj = JSONObject.parseObject(resObj.getString("data"));
                user.setUserId(obj.getString("userId"));
                user.setUserName(obj.getString("nickName"));
            } else {
                JSONObject redisObj = redisCache.getCacheObject(key);
                user.setUserId(redisObj.getString("userId"));
                user.setUserName(redisObj.getString("nickName"));
            }
        }
        return user;
    }

    /**
     * 删除用户
     *
     * @param userIdList
     * @return
     */
    @Override
    public boolean deleteUsers(List<String> userIdList) {

        for (String userId : userIdList) {
            // 删除用户角色关联
            LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserRole::getUserId, userId);
            if (userRoleService.count(queryWrapper) > 0) {
                if (!userRoleService.remove(queryWrapper)) {
                    throw new ServiceException("删除用户角色关联失败！");
                }
            }
        }

        if (!removeByIds(userIdList)) {
            throw new ServiceException("删除用户失败！");
        }

        // 删除角色与菜单关联
        // roleMenuService.remove(Wrappers.<RoleMenu>lambdaQuery().in(RoleMenu::getRoleId, idList));
        return true;
    }

    @Override
    public boolean checkUserHasLoginRole(String userId) {
        return count(Wrappers.<User>lambdaQuery()
                .eq(User::getUserId, userId)
                .eq(User::getStatus, "0")) > 0;
    }

    /**
     * 设置cache key
     *
     * @param configKey 参数键
     * @return 缓存键key
     */
    private String getCacheKey(String configKey) {
        return "sys_user:" + configKey;
    }

    /** ********************* 以下调用其他系统的 ******************************* */

    /**
     * 获取token与authstr
     *
     * @param
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject getToken(JSONObject object) {
        HttpResponse resp = HttpRequest.post(getOrderSysTokenUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            JSONObject obj = JSON.parseObject(resp.body());
            String token = obj.getString("data");
            String tmpStr = authSalt.charAt(2) + authSalt.charAt(8) + token + authSalt.charAt(10) + authSalt.charAt(5);
            object.put("token", token);
            object.put("authStr", SecureUtil.md5(tmpStr));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return object;
    }

    /**
     * 积分系统：根据url判断调用接口
     *
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject paymentAPI(JSONObject object, String url) {
        System.out.println("调用积分系统：清空钱包.................");
        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(url)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 用户系统：修改密码
     *
     * @return
     */
    public JSONObject resetPwd(JSONObject object) {
        System.out.println("调用用户系统：修改密码.................");
        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.post(resetPwdUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 用户系统：获取用户信息
     *
     * @return
     */
    public JSONObject getUserCache(String userId) {
        System.out.println("调用用户系统：获取用户信息.................");
        JSONObject obj = new JSONObject();
        HttpResponse resp = HttpRequest.get(ssoUrl + "/user/cache/" + userId)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .execute();
        try {
            obj = JSON.parseObject(resp.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

}

